// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "runtime_types.h"
#include "type.h"
#include "assert.h"
#include "map.h"

// Initialize a range over a map.

void
__go_mapiterinit(const struct __go_map *h, struct __go_hash_iter *it)
{
	it->entry = NULL;
	if (h != NULL) {
		it->map = h;
		it->next_entry = NULL;
		it->bucket = 0;
		--it->bucket;
		__go_mapiternext(it);
	}
}

// Move to the next iteration, updating *HITER.

void
__go_mapiternext(struct __go_hash_iter *it)
{
	const void *entry;

	entry = it->next_entry;
	if (entry == NULL) {
		const struct __go_map *map;
		uintptr bucket;

		map = it->map;
		bucket = it->bucket;
		while (1) {
			++bucket;
			if (bucket >= map->__bucket_count) {
				// Map iteration is complete.
				it->entry = NULL;
				return;
			}
			entry = map->__buckets[bucket];
			if (entry != NULL)
				break;
		}
		it->bucket = bucket;
	}
	it->entry = entry;
	it->next_entry = *(const void *const *)entry;
}

// Get the key of the current iteration.

void
__go_mapiter1(struct __go_hash_iter *it, unsigned char *key)
{
	const struct __go_map *map;
	const struct __go_map_descriptor *descriptor;
	const struct __go_type_descriptor *key_descriptor;
	const char *p;

	map = it->map;
	descriptor = map->__descriptor;
	key_descriptor = descriptor->__map_descriptor->__key_type;
	p = it->entry;
	__go_assert(p != NULL);
	__builtin_memcpy(key, p + descriptor->__key_offset, key_descriptor->__size);
}

// Get the key and value of the current iteration.

void
__go_mapiter2(struct __go_hash_iter *it, unsigned char *key, unsigned char *val)
{
	const struct __go_map *map;
	const struct __go_map_descriptor *descriptor;
	const struct __go_map_type *map_descriptor;
	const struct __go_type_descriptor *key_descriptor;
	const struct __go_type_descriptor *val_descriptor;
	const char *p;

	map = it->map;
	descriptor = map->__descriptor;
	map_descriptor = descriptor->__map_descriptor;
	key_descriptor = map_descriptor->__key_type;
	val_descriptor = map_descriptor->__val_type;
	p = it->entry;
	__go_assert(p != NULL);
	__builtin_memcpy(key, p + descriptor->__key_offset, key_descriptor->__size);
	__builtin_memcpy(val, p + descriptor->__val_offset, val_descriptor->__size);
}
